package org.srunpass.bitmap.repo;

import java.util.BitSet;
import java.util.LinkedList;
import java.util.List;

import org.srunpass.bitmap.condition.Condition;
import org.srunpass.bitmap.condition.EqCondition;
import org.srunpass.bitmap.condition.InCondition;
import org.srunpass.bitmap.enums.OperateTypeEnum;
import org.srunpass.bitmap.expression.Expression;
import org.srunpass.bitmap.model.BitMapModel;
import org.srunpass.bitmap.query.QueryWrapper;

/**
 * @author srunpass
 * @version Id: Computer, v 0.1 2025/6/30 14:44 srunpass Exp $
 */
public class BitMapRepoWrapper<T extends BitMapModel> {

    private final BitMapRepo<T> repo;

    public BitMapRepoWrapper(BitMapRepo<T> repo) {
        this.repo = repo;
    }

    public List<T> query(QueryWrapper wrapper) {
        return repo.getByIndex(computeExpression(wrapper.getRootExpression()));
    }

    private BitSet computeExpression(Expression root) {
        if (root.getCondition() != null) {
            return query(root.getCondition());
        }
        LinkedList<Expression> subExpressions = root.getExpressions();
        if (subExpressions == null || subExpressions.isEmpty()) {
            return new BitSet();
        }
        //计算堆栈
        LinkedList<OperateTypeEnum> opts = new LinkedList<>();
        LinkedList<BitSet> res = new LinkedList<>();
        res.push(computeExpression(subExpressions.pop()));
        while (true) {
            OperateTypeEnum nowOpt = root.getOperates().peek();
            OperateTypeEnum waitOpt = opts.peek();
            if (nowOpt == null && waitOpt == null) {
                return res.peek();
            }
            if (waitOpt == null) {
                opts.push(root.getOperates().pop());
                res.push(computeExpression(subExpressions.pop()));
                continue;
            }
            if (nowOpt == null || nowOpt.getOrder() < waitOpt.getOrder()) {
                BitSet left = res.pop();
                BitSet right = res.peek();
                compute(left, right, opts.pop());
            } else {
                opts.push(root.getOperates().pop());
                res.push(computeExpression(subExpressions.pop()));
            }
        }

    }

    private void compute(BitSet left, BitSet right, OperateTypeEnum opt) {
        switch (opt) {
            case AND:
                right.and(left);
                break;
            case OR:
                right.or(left);
                break;
            default:
                throw new IllegalArgumentException("不支持OperateTypeEnum" + opt.name());
        }
    }

    private BitSet query(Condition condition) {
        if (condition instanceof EqCondition) {
            EqCondition eq = (EqCondition) condition;
            return repo.query(eq.getField(), eq.getVal());
        } else if (condition instanceof InCondition) {
            InCondition eq = (InCondition) condition;
            return repo.query(eq.getField(), eq.getVals().toArray());
        }
        throw new IllegalArgumentException("不支持条件类型");
    }
}
